`timescale 1ns / 1ps
module sim3(
    
);


/********************clk control*******************/
reg clk_s;
reg CSorH;
reg dclk_SorH;
reg clk_h;
reg dclk_h;
wire clk;
wire clkA;
reg  clkB;
reg [7:0]   clkB_div;
reg         clkC;
wire        clk_c;
reg         decode_finish;
reg         clkD;
reg [7:0]   clkD_div;
reg ce_r, rst_n;
reg en_r;
wire en_w;
initial begin
    rst_n = 1; 
    ce_r = 1'b1;
    en_r = 1'b0;
    #200 rst_n = 0;
    #20 rst_n = 1;
    #20 ce_r = 1'b0;
    #10 en_r = 1'b1;
end

initial begin
    clk_s = 1;
    forever #25 clk_s = ~clk_s;
end

initial begin
    clk_h = 1;
    forever #8 clk_h = ~clk_h;
end

initial begin
    dclk_h = 1;
    CSorH = 1;
    forever #5 dclk_h = ~dclk_h;
end

assign clkA = clk;
assign clk = CSorH ? clk_s : (dclk_SorH ? clk_h : dclk_h);
assign clk_c = decode_finish ? clkB : clkC;

reg[7:0] CLKB_counter;
always @(posedge clkA or negedge rst_n) begin
    if (rst_n) begin
        if (CLKB_counter === 8'h02) begin
            clkB <= ~clkB;
            CLKB_counter <= 8'h00;
        end else begin
            CLKB_counter <= CLKB_counter + 1;
        end
    end else begin
        clkB <= 0;
        CLKB_counter <= 0;
    end
end

/****************************************************************/


wire[31:0]  asi_addr;
wire[2:0]   asi_burst;
wire[1:0]   asi_trans;
wire[31:0]  asi_wdata;
wire        asi_write;
wire[2:0]   asi_size;
wire[31:0]  aso_rdata;
wire        aso_ready;
wire[1:0]   aso_resp;

wire[31:0]  amo_addr;
wire[2:0]   amo_burst;
wire[1:0]   amo_trans;
wire[31:0]  amo_wdata;
wire        amo_write;
wire[2:0]   amo_size;
wire[31:0]  ami_rdata;
wire        ami_ready;
wire[1:0]   ami_resp;
wire        ami_grant;
wire        amo_busreq;

wire       mi1_next;
reg [31:0] mo1_wdata;
reg        mo1_wdata_valid;
reg [31:0] mo1_burst_addr;       
reg [2:0]  mo1_data_size;
reg        mo1_write;
reg        mo1_read;
reg [31:0] mo1_burst_data_num;
reg        mo1_icont;
wire[31:0] mi1_rdata;
wire[31:0] mi1_raddr;
wire       mi1_rdata_valid;

reg[1:0]   so1_respon;
reg[31:0]  so1_rdata;
reg        so1_rdata_valid;
reg        so1_wait_req_n;
wire[31:0] si1_address;
wire       si1_write;
wire       si1_read;
wire[11:0] su1_burst_count;
wire       si1_brust_begin;
wire       su1_lock;
wire[31:0] si1_wdata;

/*************************** sim CPU set mode**************************/
ahb_master u1_ahb_master(
	.i_hclk     (clkA                   ),
    .i_hreset_n (rst_n                  ),

    .o_haddr    (asi_addr               ),
    .o_hburst   (asi_burst              ),
    .o_htrans   (asi_trans              ),
    .o_hwdata   (asi_wdata              ),
    .o_hwrite   (asi_write              ),
    .o_hsize    (asi_size               ),
    .i_hrdata   (aso_rdata              ),
    .i_hready   (aso_ready              ),
    .i_hresp    (aso_resp               ),
    .i_hgrant   (1'b1                   ),
    .o_hbusreq  (busreq                 ),

    .o_next     (mi1_next             ),
    .i_data     (mo1_wdata            ),
    .i_dav      (mo1_wdata_valid      ),
    .i_addr     (mo1_burst_addr       ),
    .i_size     (mo1_data_size        ),
    .i_wr       (mo1_write            ),
    .i_rd       (mo1_read             ),
    .i_min_len  (mo1_burst_data_num   ),
    .i_cont     (mo1_icont            ),
    .o_data     (mi1_rdata            ),
    .o_addr     (mi1_raddr            ),
    .o_dav      (mi1_rdata_valid      )
);


reg read;
reg s1;
reg s;
wire clkr;
wire clkw;
assign clkr = read & clkB;
assign clkw = clkB & s1;

always @(posedge clkr or negedge rst_n) begin
    if (rst_n) begin
        mo1_read <= 1;
        mo1_write <= 0;
        mo1_burst_addr <= 32'h2000_0000 + 4;
        if (mi1_rdata[2:0] === 3'b111) begin
            s <= 1;
        end else if(s === 1 & mi1_rdata[2:0] === 3'b000) begin
            read <= 0;
        end 
    end else begin
        mo1_read <= 0;
        mo1_write <= 0;
        mo1_data_size <= 3'b010;
        mo1_burst_data_num <= 8'hf0;
        mo1_icont <= 0;
        read <= 1;
        s <= 0;
    end
end

reg[7:0] countt;
wire clkcr;
reg crr;
assign clkr = crr & clkB;
always @(posedge clkr or negedge rst_n) begin
    if (rst_n && read === 0) begin
        if (countt < 8'h80) begin
            mo1_read <= 0;
            mo1_write <= 0;
            countt <= countt + 1;
        end else begin
            s1 <= 1;
            crr <= 0;
        end
    end else begin
        s1 <= 0;
        countt <= 0;
        crr <= 1;
    end
end

reg sff;
reg[31:0] tempAddr;
always @(posedge clkw or negedge rst_n) begin
    if (rst_n & ~read) begin
        if(tempAddr >= 32'h1fff_ffff)begin
            mo1_read <= 0;
            mo1_write <= 1;
            mo1_burst_addr <= tempAddr;
            tempAddr <= tempAddr - 1;
            case (tempAddr)
                32'h2000_0001 : mo1_wdata <= 32'h0000_0001;
                32'h2000_0000 : mo1_wdata <= 32'h0000_0027;
                32'h1fff_ffff : mo1_wdata <= 32'h0000_000D;
                default: mo1_wdata <= mo1_wdata;
            endcase
        end else begin
            mo1_read <= 0;
            mo1_write <= 0;
            s1 <= 0;
            sff <= 1;
        end
    end else begin
        tempAddr <= 32'h2000_0002;
        mo1_wdata_valid <= 1;
        sff <= 0;
    end
end
reg s2;
wire clks2;
assign clks2 = clkB & s2;

reg[7:0] countt1;
always @(posedge clkB or negedge rst_n) begin
    if (rst_n && sff === 1) begin
        if (countt1 < 8'h80) begin
            mo1_read <= 0;
            mo1_write <= 0;
            countt1 <= countt1 + 1;
        end else begin
            s2 <= 1;
        end
    end else begin
        s2 <= 0;
        countt1 <= 0;
    end
end

reg[31:0] tempAddr1;
reg[31:0] afd;

reg s3;
wire clks3;
assign clks3 = s3 & clkB;

always @(posedge clks2 or negedge rst_n) begin
    if (rst_n & ~s1) begin
        if(tempAddr1 >= 32'h1fff_ffff)begin
            
            mo1_read <= 0;
            mo1_write <= 1;
            mo1_burst_addr <= tempAddr1;
            tempAddr1 <= tempAddr1 - 1;
            case (tempAddr1)
                32'h2000_0002 : mo1_wdata <= 32'h0000_0001;
                32'h2000_0001 : mo1_wdata <= 32'h0000_0001;
                32'h2000_0000 : mo1_wdata <= 32'h0000_4001;
                32'h1fff_ffff : mo1_wdata <= 32'h0000_0005;
                default: mo1_wdata <= mo1_wdata;
            endcase
        end else begin
            mo1_read <= 0;
            mo1_write <= 0;
            if(afd <= 8000)begin
                afd <= afd + 1;
            end else begin
                s2 <= 0;
                s3 <= 1;
            end
        end
    end else begin
        tempAddr1 <= 32'h2000_0003;
        mo1_wdata_valid <= 1;
        afd <=0;
        s3 <= 0;
    end
end


reg[31:0] tempAddr2;
always @(posedge clks3 or negedge rst_n) begin
    if (rst_n) begin
            crr <= 0;
            s1 <= 0;
            s2 <= 0;
            sff <= 0;
        if(tempAddr2 >= 32'h1fff_ffff)begin
            mo1_read <= 0;
            mo1_write <= 1;
            mo1_burst_addr <= tempAddr2;
            tempAddr2 <= tempAddr2 - 1;
            case (tempAddr2)
                32'h2000_0002 : mo1_wdata <= 32'h0000_0001;
                32'h2000_0001 : mo1_wdata <= 32'h0000_0001;
                32'h2000_0000 : mo1_wdata <= 32'h0000_4001;
                32'h1fff_ffff : mo1_wdata <= 32'h0000_0003;
                default: mo1_wdata <= mo1_wdata;
            endcase
        end else begin
            mo1_read <= 0;
            mo1_write <= 0;
            s3 <= 0;
        end
    end else begin
        tempAddr2 <= 32'h2000_0003;
    end
end

/*******************************************************************/

/***************mod RAM read or wrote Data***********************/



AHB_slave u_AHB_slave(
	.clk                    (clkB           ),
    .reset_n                (rst_n          ),

    .ahb_haddr              (amo_addr           ),
    .ahb_hburst             (amo_burst          ),
    .ahb_htrans             (amo_trans          ),
    .ahb_hwdata             (amo_wdata          ),
    .ahb_hwrite             (amo_write          ),
    .ahb_hsize              (amo_size           ),
    .ahb_hrdata             (ami_rdata          ),
    .ahb_hready             (ami_ready          ),
    .ahb_hresp              (ami_resp[0]        ),
    .ahb_hmastlock          (1'b1           ),
    .ahb_hprot              (4'h00          ),

    .avl_readdata           (so1_rdata        ),
    .avl_readdatavalid      (so1_rdata_valid  ),
    .avl_waitrequest_n      (so1_wait_req_n   ),
    .avl_response           (so1_respon       ),
    .avl_address            (si1_address      ),
    .avl_write              (si1_write        ),
    .avl_read               (si1_read         ),
    .avl_burstcount         (su1_burst_count  ),
    .avl_beginbursttransfer (si1_brust_begin  ),
    .avl_lock               (su1_lock         ),
    .avl_writedata          (si1_wdata        )
);

reg[7:0] dta;
always @(negedge clkB or rst_n) begin
    if (rst_n) begin
        so1_rdata_valid <= 1;
        if (si1_read === 1) begin
            so1_rdata <= $random();
           // so1_rdata[7:0] <= dta + 3;
           // so1_rdata[15:8] <= dta + 2;
           // so1_rdata[23:16] <= dta + 1;
           // so1_rdata[31:24] <= dta;
            dta <= dta + 4;
        end else begin
            so1_rdata <= so1_rdata;
            dta <= dta;
        end
    end else begin
        so1_wait_req_n <= 1;
        so1_rdata_valid <= 0;
        dta <= 0;
        so1_respon <= 1'b0;
    end
end
/*******************************************************************/


reg[3:0] portMode;

parameter CMD_RESET =                 8'hFF;
parameter CMD_READ_ID =               8'h90;
parameter CMD_READ_STATUS =           8'h70;
parameter CMD_READ_PAGE_C0 =          8'h00;
parameter CMD_READ_PAGE_C1 =          8'h30;
parameter CMD_READ_PAGE_CACHE =       8'h31;
parameter CMD_READ_PAGE_CACHE_CASE =  8'h3f;
parameter CMD_READ_MUL_C0 =           8'h00;
parameter CMD_READ_MUL_C1 =           8'h32;
parameter CMD_PROG_PAGE_C0 =          8'h80;
parameter CMD_PROG_PAGE_C1 =          8'h10;
parameter CMD_PROG_PAGE_CACHE_C0 =    8'h80;
parameter CMD_PROG_PAGE_CACHE_C1 =    8'h15;
parameter CMD_PROG_PAGE_MUL_C0 =      8'h80;
parameter CMD_PROG_PAGE_MUL_C1 =      8'h11;
parameter CMD_ERASE_BLOCK_CO =        8'h60;
parameter CMD_ERASE_BLOCK_C1 =        8'hD0;
parameter CMD_ERASE_BLOCK_MUL_C0 =    8'h60;
parameter CMD_ERASE_BLOCK_MUL_C1 =    8'hD1;
parameter CMD_GET_FEATURES =          8'hee;
parameter CMD_SET_FEATURES =          8'hef;


parameter State_command =   3'b000;
parameter State_adderss =   3'b001;
parameter State_WriteData = 3'b010;
parameter State_ReadData  = 3'b011;
parameter State_Idle =      3'b100;
parameter State_WriteWait = 3'b111;

parameter PAGE_SIZE = 32'h484;//data size + spare size
parameter SPARE_SIZE = 8'h84;

reg[2:0]  port_cmd_reg;
reg[7:0]  port_data_in_reg;
wire      port_data_in_en;
wire[7:0] port_data_out_reg;
wire      port_data_out_vaild;

wire[31:0] port_data_number;
wire[31:0] port_data_counter;

reg[31:0] read_data_number;
reg[31:0] read_data_counter;

reg[31:0] write_data_number;
reg[31:0] write_data_counter;

wire we_s_w;
wire re_s_w;
wire cle_w;
wire ale_w;
wire[7:0] dq_w;
wire dqs_w;
wire rb_s_w;

reg    wp_r;
reg    dclk_r;

reg[39:0] address_reg;
reg[31:0] features_reg;
reg       reg_is_refreshed;

/***********************************AHB module**************************/
//reg define 
reg[31:0] reg0;
//mode control register 
reg[31:0] reg1;
// col addr reg(bolck addr)
reg[31:0] reg2;
// row addr reg(page addr) 
reg[31:0] reg3;
// read or write addr from RAM
reg[31:0] reg4;
// state register read only
reg[31:0] reg5;
//reservation

wire[31:0] i_reg0;
wire[31:0] i_reg1;
wire[31:0] i_reg2;
wire[31:0] i_reg3;
wire[31:0] i_reg4;
wire[31:0] i_reg5;

wire rorw;
wire ref;

assign i_reg0 = rorw ? reg0 : 32'hzzzz_zzzz;
assign i_reg1 = rorw ? reg1 : 32'hzzzz_zzzz;
assign i_reg2 = rorw ? reg2 : 32'hzzzz_zzzz;
assign i_reg3 = rorw ? reg3 : 32'hzzzz_zzzz;
assign i_reg4 = rorw ? reg4 : 32'hzzzz_zzzz;
assign i_reg5 = rorw ? reg5 : 32'hzzzz_zzzz;

AHBslave2Reg u_AHBslave2Reg(
	.clk     (clkB    ),
    .rst_n   (rst_n   ),

    .HADDR   (asi_addr   ),
    .HWRITE  (asi_write  ),
    .HSIZE   (asi_size   ),
    .HBURST  (asi_burst  ),
    .HTRANS  (asi_trans  ),
    .HWDATA  (asi_wdata  ),
    .HREADY  (aso_ready  ),
    .HRESP   (aso_resp   ),
    .HRDATA  (aso_rdata  ),

    .io_reg0 (i_reg0 ),
    .io_reg1 (i_reg1 ),
    .io_reg2 (i_reg2 ),
    .io_reg3 (i_reg3 ),
    .io_reg4 (i_reg4 ),
    .io_reg5 (i_reg5 ),
    .r_or_w  (rorw    ),
    .refresh (ref     )
);

wire       mi_next;
reg [31:0] mo_wdata;
reg        mo_wdata_valid;
reg [31:0] mo_burst_addr;       
reg [2:0]  mo_data_size;
reg        mo_write;
reg        mo_read;
reg [31:0] mo_burst_data_num;
reg        mo_icont;
wire[31:0] mi_rdata;
wire[31:0] mi_raddr;
wire       mi_rdata_valid;

ahb_master u_ahb_master(
	.i_hclk     (clkB               ),
    .i_hreset_n (rst_n              ),

    .o_haddr    (amo_addr               ),
    .o_hburst   (amo_burst              ),
    .o_htrans   (amo_trans              ),
    .o_hwdata   (amo_wdata              ),
    .o_hwrite   (amo_write              ),
    .o_hsize    (amo_size               ),
    .i_hrdata   (ami_rdata              ),
    .i_hready   (ami_ready              ),
    .i_hresp    (ami_resp               ),
    .i_hgrant   (1'b1                   ),
    .o_hbusreq  (amo_busreq             ),

    .o_next     (mi_next             ),
    .i_data     (mo_wdata            ),
    .i_dav      (mo_wdata_valid      ),
    .i_addr     (mo_burst_addr       ),
    .i_size     (mo_data_size        ),
    .i_wr       (mo_write            ),
    .i_rd       (mo_read             ),
    .i_min_len  (mo_burst_data_num   ),
    .i_cont     (mo_icont            ),
    .o_data     (mi_rdata            ),
    .o_addr     (mi_raddr            ),
    .o_dav      (mi_rdata_valid      )
);

always @(negedge ref or negedge rst_n) begin
    if (rst_n) begin
        reg1 <= i_reg1;
        reg2 <= i_reg2;
        reg3 <= i_reg3;
    //    reg4 <= i_reg4;
     //   reg5 <= i_reg5;
     if (reg0 === i_reg0) begin
         reg_is_refreshed <= reg_is_refreshed;
     end else begin
         reg0 <= i_reg0;
         reg_is_refreshed <= 1;
     end
    end else begin
         reg0 <= 0;
         reg1 <= 0;
         reg2 <= 0;
         reg3 <= 0;
         reg4 <= 32'hffff_ffff;
         reg5 <= 0;
    end
end

always @(posedge ref) begin
    reg1 <= i_reg1;
    reg2 <= i_reg2;
    reg3 <= i_reg3;
    if (reg0 === i_reg0) begin
         reg_is_refreshed <= reg_is_refreshed;
     end else begin
         reg0 <= i_reg0;
         reg_is_refreshed <= 1;
     end
   // reg4 <= i_reg4;
  //  reg5 <= i_reg5;
end
/***********************************************************************/
reg ldpc_wen;
reg ldpc_ren;
reg[95:0] ldpc_dataIn;
reg ldpc_code_en;
reg ldpc_decode_en;
wire[95:0] ldpc_dataOut;
wire ldpc_state;
wire ldpc_code_finish;
wire ldpc_decode_finish; 

ldpc_top u_ldpc_top(
	.i_rst_n         (rst_n              ),
    .i_ldpc_clk      (clk                ),

    .i_clk           (clk_c              ),
    .i_w_en          (ldpc_wen           ),
    .i_r_en          (ldpc_ren           ),
    .i_data          (ldpc_dataIn        ),
    .i_code_en       (ldpc_code_en       ),
    .i_dcd_en        (ldpc_decode_en     ),
    .o_data          (ldpc_dataOut       ),
    .o_status        (ldpc_state         ),
    .o_code_finish   (ldpc_code_finish   ),
    .o_dcd_finish    (ldpc_decode_finish )
);

/*********************** flash mode port **************************/
nand_model u_nand_model(
    .Dq_Io     (dq_w     ),
    .Dqs       (dqs_w    ),
    .Cle       (cle_w    ),
    .Ale       (ale_w    ),
    .Ce_n      (ce_r     ),
    .Clk_We_n  (we_s_w   ),
    .Wr_Re_n   (re_s_w   ),
    .Wp_n      (wp_r     ),
    .Rb_n      (rb_s_w   ),
    .ENi       (en_r     ),
    .ENo       (wn_w     ),
    .Dqs_c     (    ),
    .Re_c      (1'b1     )
);

/*********************** toggle mode port **************************/
Toggle_port u_Toggle_port(
	.WE_s          (we_s_w      ),
    .RE_s          (re_s_w      ),
    .CLE           (cle_w       ),
    .ALE           (ale_w       ),
    .DQ            (dq_w        ),
    .DQS           (dqs_w       ),
    .RB            (rb_s_w      ),

    .clkX2         (clk                 ),
    .dclk          (dclk_r              ),
    .rst_n         (rst_n               ),
    .en            (portMode[0]         ),
    .Cmd           (port_cmd_reg        ),
    .InputVal      (port_data_in_reg    ),
    .IV_En         (port_data_in_en     ),
    .ReadVal       (port_data_out_reg   ),
    .RV_En         (port_data_out_vaild ),
    .RWDataNum     (port_data_number    ),
    .RWDataCounter (port_data_counter   )
);
/*********************** async mode cycle **************************/
Async_port u_Async_port(
	.WE_s          (we_s_w          ),
    .RE_s          (re_s_w          ),
    .CLE           (cle_w           ),
    .ALE           (ale_w           ),
    .DQ            (dq_w            ),
    .RB            (rb_s_w          ),

    .clkX2         (clk                 ),
    .dclk          (dclk_r              ),
    .rst_n         (rst_n               ),
    .en            (portMode[1]         ),
    .Cmd           (port_cmd_reg        ),
    .InputVal      (port_data_in_reg    ),
    .IV_En         (port_data_in_en     ),
    .ReadVal       (port_data_out_reg   ),
    .RV_En         (port_data_out_vaild ),
    .RWDataNum     (port_data_number    ),
    .RWDataCounter (port_data_counter   )
);

/*********************** sync mode cycle **************************/
Sync_port u_Sync_port(
	.CLK           (we_s_w      ),
    .WR            (re_s_w      ),
    .CLE           (cle_w       ),
    .ALE           (ale_w       ),
    .DQ            (dq_w        ),
    .DQS           (dqs_w       ),
    .RB            (rb_s_w      ),

    .clkX2         (clk                 ),
    .dclk          (dclk_r              ),
    .rst_n         (rst_n               ),
    .en            (portMode[2]         ),
    .Cmd           (port_cmd_reg        ),
    .InputVal      (port_data_in_reg    ),
    .IV_En         (port_data_in_en     ),
    .ReadVal       (port_data_out_reg   ),
    .RV_En         (port_data_out_vaild ),
    .RWDataNum     (port_data_number    ),
    .RWDataCounter (port_data_counter   )
);
/*********************** nvddr2 mode cycle **************************/
ddr2_port u_ddr2_port(
	.WE_s          (we_s_w      ),
    .RE_dif        (re_s_w      ),
    .CLE           (cle_w       ),
    .ALE           (ale_w       ),
    .DQ            (dq_w        ),
    .DQS_dif       (dqs_w       ),
    .RB            (rb_s_w      ),

    .clkX2         (clk                  ),
    .dclk          (dclk_r               ),
    .rst_n         (rst_n                ),
    .en            (portMode[3]          ),
    .Cmd           (port_cmd_reg         ),
    .InputVal      (port_data_in_reg     ),
    .IV_En         (port_data_in_en      ),
    .ReadVal       (port_data_out_reg    ),
    .RV_En         (port_data_out_vaild  ),
    .RWDataNum     (port_data_number     ),
    .RWDataCounter (port_data_counter    )
);

localparam RESET =        6'b000001;
localparam READ_PAGE =    6'b000010;
localparam WRITE_PAGE =   6'b000100;
localparam READ_ID =      6'b001000;  
localparam ERASE_BLOCK =  6'b010000;
localparam GET_FEATURES = 6'b100000;
localparam SET_FEATRES  = 6'b110000;
localparam IDLE =         6'b000000;

parameter tWB = 8'h03;
parameter tWW = 8'h10;
parameter tADL = 8'h09;

reg[5:0] cur_state;
reg       ecc_ready;
initial begin
        wp_r = 1'b1;

    //#2009200 ecc_ready = 1'b1;
end

/*
initial begin
    cur_state = IDLE;
    portMode = 4'b0010;
    CSorH = 1;
    #300  cur_state = RESET;
    #2000500 cur_state = SET_FEATRES;
    features_reg = 32'h00_00_00_27;
    address_reg = 32'h00_00_00_01;

    #3095 cur_state = GET_FEATURES;
    address_reg = 32'h00_00_00_01;
    portMode = 4'b1000;
    CSorH = 0;

    #3000 cur_state = WRITE_PAGE;
    //address_reg = 40'h00_40_00_00_00;
    #1732450 cur_state = READ_PAGE;
    address_reg = 40'h00_40_00_00_00;
                //    r3 r2 r1      c0 c1
                //   block addr   page addr
    #1732450 cur_state = WRITE_PAGE;
    address_reg = 40'h00_40_00_00_00;
end*/

reg      address_cycle;
reg      command_cycle;
reg      read_data_cycle;
reg      write_data_cycle;
reg      delay_cycle;
reg      wait_rnb_cycle;

reg      cur_cycle_finish;
reg      read_page_finish;//读页周期完成
reg      write_page_finish;//写页周期完成
reg      erase_block_finish;
reg      read_id_finish;
reg      get_features_finish;
reg      set_features_finish;
reg      reset_finish;

reg      rst_cmd_finish;

reg[7:0] data_r_a;
reg[7:0] data_r_c;
reg[7:0] data_r_rd;
reg[7:0] data_r_wd;

reg[7:0] cmd_r_a;
reg[7:0] cmd_r_c;
reg[7:0] cmd_r_rd;
reg[7:0] cmd_r_wd;

reg      add_cycle_tri_n;  //地址周期触发信号，下降沿触发
reg      add_cycle_fin_n;  //地址周期完成信号，下降沿有效
reg      cmd_cycle_tri_n;
reg      cmd_cycle_fin_n;
reg      rd_cycle_tri_n;
reg      rd_cycle_fin_n;
reg      wd_cycle_tri_n;
reg      wd_cycle_fin_n;
reg      dly_cycle_tri_n;
reg      dly_cycle_fin_n;
reg      wait_rnb_tri_n;
reg      wait_rnb_fin_n;

reg[7:0] command_reg;

reg rd_address_cycle_finish;
reg eb_address_cycle_finish;
reg wd_command_cycle_finish;
reg wd_address_cycle_finish;

reg[3:0] address_number;
reg[8:0] delay_number;

reg rd_rst_n;
reg wd_rst_n;
reg eb_rst_n;
reg rid_rst_n;
reg rst_rst_n;
reg get_features_rst_n;
reg set_features_rst_n;

reg state_changed_n;

always @(*) begin
    if (address_cycle === 0) begin
        port_data_in_reg = data_r_a;
        port_cmd_reg = cmd_r_a;
    end else if(command_cycle === 0) begin
        port_data_in_reg = data_r_c;
        port_cmd_reg = cmd_r_c;
    end else if(read_data_cycle === 0) begin
        port_cmd_reg = cmd_r_rd;
        port_data_in_reg = data_r_rd;
    end else if(write_data_cycle === 0) begin
        port_cmd_reg = cmd_r_wd;
        port_data_in_reg = data_r_wd;
    end else begin
        port_cmd_reg = State_Idle;
        port_data_in_reg = 8'h00;
    end
end

always @(*) begin
    if ( (write_data_cycle === 0 | read_data_cycle === 0)) begin
        dclk_SorH = 0;
    end else begin
        dclk_SorH = 1;
    end
end

assign port_data_number = cur_state === WRITE_PAGE ? write_data_number : read_data_number;
assign port_data_counter = cur_state === WRITE_PAGE ? write_data_counter : read_data_counter;

always @(*) begin
    case (cur_state)
       READ_PAGE : begin
            //address_reg = 40'h00_40_00_00_00;
            address_reg = {reg2[7:0], reg2[15:8], reg1[7:0], reg1[15:8], reg1[23:16]};
            cur_cycle_finish = read_page_finish;
            address_number = 4'h5;
            delay_number = tWB;
            read_data_number = PAGE_SIZE;
            if (rd_address_cycle_finish) begin  
                command_reg = CMD_READ_PAGE_C1;
                cmd_cycle_tri_n = add_cycle_fin_n;  
                dly_cycle_tri_n = cmd_cycle_fin_n; 
                wait_rnb_tri_n = dly_cycle_fin_n;  
                rd_cycle_tri_n = wait_rnb_fin_n;   
            end else begin
                command_reg = CMD_READ_PAGE_C0;
                rd_rst_n = state_changed_n;
                cmd_cycle_tri_n = rd_rst_n;        
                add_cycle_tri_n = cmd_cycle_fin_n; 
            end
       end 
       WRITE_PAGE : begin
            address_reg = {reg2[7:0], reg2[15:8], reg1[7:0], reg1[15:8], reg1[23:16]};
            //address_reg = 40'h00_40_00_00_00;
            address_number = 4'h5;
            cur_cycle_finish = write_page_finish;
            write_data_number = PAGE_SIZE;
            if (wd_address_cycle_finish & wd_command_cycle_finish === 0) begin
                delay_number = tADL;
                command_reg = CMD_PROG_PAGE_C1;

                dly_cycle_tri_n = add_cycle_fin_n;
                wd_cycle_tri_n = dly_cycle_fin_n;
                cmd_cycle_tri_n = wd_cycle_fin_n;   
            end else if (wd_command_cycle_finish) begin    
                delay_number = tWB; 
                dly_cycle_tri_n = cmd_cycle_fin_n;  
                wait_rnb_tri_n = dly_cycle_fin_n;   
            end else begin
                delay_number = tWW;
                command_reg = CMD_PROG_PAGE_C0;

                wd_rst_n = state_changed_n;
                dly_cycle_tri_n = wd_rst_n;
                cmd_cycle_tri_n = dly_cycle_fin_n;         
                add_cycle_tri_n = cmd_cycle_fin_n;  
            end
       end
       READ_ID : begin
           address_reg = 40'h00_00_00_00_20;
           cur_cycle_finish = read_id_finish;
           address_number = 8'h01;
           read_data_number = 8'h04;
           command_reg = CMD_READ_ID;
           rid_rst_n = state_changed_n;
           cmd_cycle_tri_n = rid_rst_n;
           add_cycle_tri_n = cmd_cycle_fin_n;
           rd_cycle_tri_n = add_cycle_fin_n;
       end
       RESET : begin
           cur_cycle_finish = reset_finish;
           command_reg = CMD_RESET; 
           rst_rst_n = state_changed_n;    
           if(rst_cmd_finish)begin
                delay_number = tWB;
                dly_cycle_tri_n = cmd_cycle_fin_n;   
                wait_rnb_tri_n = dly_cycle_fin_n;   
           end else begin
                delay_number = 8'hff;
                dly_cycle_tri_n = rst_rst_n;
                wait_rnb_tri_n = dly_cycle_fin_n;
                cmd_cycle_tri_n = wait_rnb_fin_n;
           end       
       end
       ERASE_BLOCK : begin
           address_number = 4'h3;
           cur_cycle_finish = erase_block_finish;
           if (eb_address_cycle_finish) begin
               command_reg = CMD_ERASE_BLOCK_C1;
               cmd_cycle_tri_n = add_cycle_fin_n;
           end else begin
               eb_rst_n = state_changed_n;
               cmd_cycle_tri_n = eb_rst_n;
               command_reg = CMD_ERASE_BLOCK_CO;
               add_cycle_tri_n = cmd_cycle_fin_n;
           end
       end
       GET_FEATURES : begin
           address_number = 8'h01;
           read_data_number = 8'h04;
           delay_number = tWB;

           cur_cycle_finish = get_features_finish;
           command_reg = CMD_GET_FEATURES;
           get_features_rst_n = state_changed_n;
           cmd_cycle_tri_n = get_features_rst_n;
           add_cycle_tri_n = cmd_cycle_fin_n;
           dly_cycle_tri_n = add_cycle_fin_n;
           wait_rnb_tri_n = dly_cycle_fin_n;
           rd_cycle_tri_n = wait_rnb_fin_n;
       end
       SET_FEATRES : begin
           address_number = 8'h01;
           write_data_number = 8'h04;
           delay_number = 8'h02;
           cur_cycle_finish = set_features_finish;
           command_reg = CMD_SET_FEATURES;
           set_features_rst_n = state_changed_n;
           cmd_cycle_tri_n = set_features_rst_n;
           add_cycle_tri_n = cmd_cycle_fin_n;
           wd_cycle_tri_n = add_cycle_fin_n;
           dly_cycle_tri_n = wd_cycle_fin_n;
           wait_rnb_tri_n = dly_cycle_fin_n;
       end
        default: begin
            cur_cycle_finish = 1'b0;
            add_cycle_tri_n = 1'b1;
        end
    endcase
end

always @(*) begin
    //if (cur_state === WRITE_PAGE ) begin
  //  end else begin
  //      #400wp_r = 1'b0;        
   // end
end


/*********************** dclk control **************************/
always @(posedge clk or negedge rst_n) begin
    if (rst_n != 1'b0) begin
        dclk_r <= ~dclk_r; 
    end else begin
        dclk_r <= 1'b1;
    end
end

/****************************main**********************************/
always @(posedge clk or negedge rst_n) begin
    if (rst_n) begin
        if(cur_state === IDLE && reg_is_refreshed && reg0[0])begin
            case (reg0[4:1])
               3'b000 : cur_state <= IDLE;
               3'b001 : cur_state <= READ_PAGE;
               3'b010 : cur_state <= WRITE_PAGE;
               3'b011 : cur_state <= ERASE_BLOCK;
               3'b100 : cur_state <= READ_ID;
               3'b101 : cur_state <= GET_FEATURES;
               3'b110 : cur_state <= SET_FEATRES;
               3'b111 : cur_state <= RESET;
               default: cur_state <= IDLE;
            endcase
            reg4[2:0] <= 3'b111;
        end else begin
            if (cur_cycle_finish) begin
                cur_state <= IDLE;
                reg_is_refreshed <= 0;
                reg4[2:0] <= 3'b000;
            end else begin
                cur_state <= cur_state;
            end
        end
        
    end else begin
        cur_state <= RESET;
        portMode <= 4'b0010;
      //  reg4[3:0] <= 32'hffff_ffff;
        cur_cycle_finish <= 0;
    end
end

/*********************** read page **************************/



always @(posedge address_cycle or negedge rd_rst_n) begin
    if (rd_rst_n & cur_state === READ_PAGE) begin
        rd_address_cycle_finish <= 1'b1;
    end else begin
        rd_address_cycle_finish <= 1'b0;
    end
end

always @(posedge read_data_cycle or negedge rd_rst_n)begin
    if (rd_rst_n & cur_state === READ_PAGE & rd_address_cycle_finish) begin
        read_page_finish <= 1'b1;
    end else begin
        read_page_finish <= 1'b0;
    end
end
/***********************coding decoding **************************/
reg[31:0]  AHBraddr_det;
reg[31:0]  AHBwaddr_det;

parameter READ_FIFO_SIZE = 256;
reg[READ_FIFO_SIZE - 1:0] AHBread_fifo;
reg[31:0]  AHBread_fifo_counter;
reg[31:0]  ECCread_fifo_counter;
reg        waite_for_AHBread;

always @(negedge clkB or negedge rst_n) begin
    if (cur_state === WRITE_PAGE & rst_n) begin
        if (mi_rdata_valid  === 1) begin
            AHBread_fifo <= {AHBread_fifo[READ_FIFO_SIZE - 32:0],mi_rdata};
            AHBread_fifo_counter <= AHBread_fifo_counter + 32;
            ECCread_fifo_counter <= ECCread_fifo_counter + 32;
            waite_for_AHBread <= 0;
        end else begin
            AHBread_fifo <= AHBread_fifo;
            AHBread_fifo_counter <= AHBread_fifo_counter;
            ECCread_fifo_counter <= ECCread_fifo_counter;
            waite_for_AHBread <= waite_for_AHBread;
        end
    end else begin
        AHBread_fifo <= AHBread_fifo;     
        AHBread_fifo_counter <= 0;
        ECCread_fifo_counter <= 0;
        waite_for_AHBread <= 0;    
    end
end

parameter WRITE_FIFO_SIZE = 4096;
reg[WRITE_FIFO_SIZE - 1:0] AHBwrite_fifo;
reg[31:0]  AHBwrite_fifo_counter;

always @(posedge clkB or negedge rst_n) begin
    if (AHBwrite_fifo_counter !== 0 & rst_n) begin
        if (AHBwrite_fifo_counter >= 32) begin
            mo_wdata_valid <= 1;
            mo_wdata <= AHBwrite_fifo >> (AHBwrite_fifo_counter - 32);
            AHBwrite_fifo_counter <= AHBwrite_fifo_counter - 32;
            mo_burst_addr <= reg3 + AHBwaddr_det;
            AHBwaddr_det <= AHBwaddr_det + 1;
        end else begin
            mo_wdata_valid <= 0;
        end
    end else begin
        AHBwrite_fifo_counter <= 0;
        AHBwrite_fifo <= 0;
    end
end

//mode ahb master control
always @(posedge clkB) begin
    if (cur_state === WRITE_PAGE & wd_command_cycle_finish === 0) begin
        AHBwaddr_det <= 0;
        //mo_burst_addr <= reg3;
        if (mi_next === 1 && AHBraddr_det < ((PAGE_SIZE - SPARE_SIZE) >> 2) ) begin
            mo_read <= 1;
            mo_write <= 0;
            mo_burst_addr <= reg3 + AHBraddr_det;
            AHBraddr_det <= AHBraddr_det + 1;
        end else begin
            mo_read <= 0;
            mo_write <= 0;
        end
    end else if (AHBwrite_fifo_counter !== 0) begin //& ecc_finish === 1
        AHBraddr_det <= 0;
        mo_read <= 0;
        mo_write <= 1;
       // mo_burst_addr <= reg3 + AHBwaddr_det;
       // AHBwaddr_det <= AHBwaddr_det + 1;
    end else begin
        mo_burst_data_num <= 8'hf0;
        mo_data_size <= 3'b010;
        mo_icont <= 0;
        mo_wdata <= 8'h00;
        mo_read <= 0;
        mo_write <= 0;
        AHBwaddr_det <= 0;
        AHBraddr_det <= 0;
    end 
end

/**************************LDPC coding*****************************/

reg[3:0] clkc_counter;
reg[15:0] code_send_data; 

task ldpc_clk_gen;
    if (clkc_counter === 1) begin
        clkC <= 0;
        clkc_counter <= clkc_counter + 1;
    end else if (clkc_counter === 2) begin
        clkC <= 1;
        clkc_counter <= 0;
    end else begin
        clkc_counter <= clkc_counter + 1;
    end
endtask

task ldpc_code_send_data;
    if(clkc_counter === 0) begin
        if (ECCread_fifo_counter >= 96) begin
            code_send_data <= code_send_data + 12;
            ldpc_wen <= 1;
            ldpc_code_en <= 1;
            ldpc_dataIn <= AHBread_fifo >> (ECCread_fifo_counter - 96);
            ECCread_fifo_counter <= ECCread_fifo_counter - 96;
        end else if(code_send_data === 1020 && ECCread_fifo_counter >= 32) begin
            code_send_data <= code_send_data + 4;
            ldpc_wen <= 1;
            ldpc_code_en <= 1;
            ldpc_dataIn <= (AHBread_fifo << 64) ^ 64'hffff_ffff;
            ECCread_fifo_counter <= ECCread_fifo_counter - 32;
        end else begin
            if(code_send_data >= 1024)begin
                ldpc_code_en <= 0;
                code_send_data <= code_send_data + 1;
            end
            ldpc_wen <= 0;
        end
    end
endtask

parameter LDPC_CODEREAD_SIZE = 1200;
reg[LDPC_CODEREAD_SIZE - 1 : 0] LDPC_CODEREAD_FIFO;
reg[16:0] ldpc_codeRead_FIFOcounter;

reg[3:0] ldpc_codeRead_num;
reg      ldpc_coderead_jmp;

task ldpc_code_rece_data;
    if (ldpc_code_finish === 1) begin
        ldpc_ren <= 1;
        if (clkc_counter === 1) begin
            if (ldpc_codeRead_num < 11 & ldpc_coderead_jmp === 1) begin
                LDPC_CODEREAD_FIFO <= {LDPC_CODEREAD_FIFO[LDPC_CODEREAD_SIZE - 96 : 0], ldpc_dataOut};
                ldpc_codeRead_FIFOcounter <= ldpc_codeRead_FIFOcounter + 96;
                ldpc_codeRead_num <= ldpc_codeRead_num + 1;
            end else if (ldpc_coderead_jmp === 0)begin
                ldpc_coderead_jmp <= 1;
            end else begin
                ecc_ready <= 1;  
            end
        end
    end else begin
        ldpc_ren <= 0;
    end
endtask

always @(posedge clk or negedge rst_n) begin
    if (rst_n & cur_state === WRITE_PAGE) begin
        ldpc_clk_gen;
        if (code_send_data <= 1024) begin
            ldpc_code_send_data;
        end else begin
            ldpc_code_rece_data;
        end
    end else begin
        ldpc_codeRead_FIFOcounter <= 0;
        ecc_ready <= 0;
        decode_finish <= 0;
        clkc_counter <= 1;
        ldpc_wen <= 0;
        ldpc_ren <= 0;
        code_send_data <= 0;
        ldpc_code_en <= 0;
        ldpc_coderead_jmp <= 0;
        ldpc_codeRead_num <= 0;
    end
end

always @(negedge clk or negedge rst_n) begin
    if (rst_n & cur_state === WRITE_PAGE) begin
        ldpc_clk_gen;
        if (code_send_data <= 1024) begin
            ldpc_code_send_data;
        end else begin
            ldpc_code_rece_data;
        end
    end else begin
        decode_finish <= 0;
        clkc_counter <= 0;
    end
end
/**********************LDPC decoding***************************/




/*********************write page ***************************/

always @(posedge command_cycle or negedge wd_rst_n) begin
    if (wd_rst_n & cur_state === WRITE_PAGE & wd_address_cycle_finish === 1) begin
        wd_command_cycle_finish <= 1'b1;
    end else begin
        wd_command_cycle_finish <= 1'b0;
    end
end

always @(posedge address_cycle or negedge rd_rst_n) begin
    if (wd_rst_n & cur_state === WRITE_PAGE) begin
        wd_address_cycle_finish <= 1'b1;
    end else begin
        wd_address_cycle_finish <= 1'b0;
    end
end

always @(posedge wait_rnb_fin_n or negedge wd_rst_n)begin
    if (wd_rst_n & cur_state === WRITE_PAGE & wd_command_cycle_finish) begin
        write_page_finish <= 1'b1;
    end else begin
        write_page_finish <= 1'b0;
    end
end

/********************erase block******************************/

always @(posedge address_cycle or negedge eb_rst_n) begin
    if (eb_rst_n & cur_state === ERASE_BLOCK) begin
        eb_address_cycle_finish <= 1'b1;
    end else begin
        eb_address_cycle_finish <= 1'b0;
    end
end

always @(posedge cmd_cycle_fin_n or negedge eb_rst_n)begin
    if (eb_rst_n & cur_state === ERASE_BLOCK & eb_address_cycle_finish) begin
        erase_block_finish <= 1'b1;
    end else begin
        erase_block_finish <= 1'b0;
    end
end

/************************read id ******************************/

always @(posedge rd_cycle_fin_n or negedge rid_rst_n)begin
    if (rid_rst_n & cur_state === READ_ID) begin
        read_id_finish <= 1'b1;
    end else begin
        read_id_finish <= 1'b0;
    end
end

/**********************get features****************************/

always @(posedge read_data_cycle or negedge get_features_rst_n) begin
    if (get_features_rst_n & cur_state === GET_FEATURES) begin
        get_features_finish <= 1'b1;
        reg5 <= features_reg;
    end else begin
        get_features_finish <= 1'b0;
        address_reg <= {32'h0000_0000,reg2[7:0]};
    end
end

/**********************set features****************************/

reg[1:0] feat;
always @(posedge wait_rnb_cycle or negedge set_features_rst_n) begin
    if (set_features_rst_n & cur_state === SET_FEATRES) begin
        set_features_finish <= 1'b1;
        case (feat)
           2'b00 : portMode <= 4'b0010;
           2'b01 : portMode <= 4'b0100;
           2'b10 : portMode <= 4'b1000;
            default: portMode <= portMode;
        endcase
    end else begin
        set_features_finish <= 1'b0;
        features_reg <= reg1;
        feat <= reg1[5:4];
        address_reg <= {32'h0000_0000, reg2[7:0]}; 
    end
end

/**************************reset******************************/

always @(posedge command_cycle or negedge rst_rst_n) begin
    if (rst_rst_n & cur_state === RESET) begin
        rst_cmd_finish <= 1;
    end else begin
        rst_cmd_finish <= 0;
    end
end

always @(posedge wait_rnb_cycle or negedge rst_rst_n) begin
    if (rst_rst_n & cur_state === RESET & rst_cmd_finish === 1) begin
        reset_finish <= 1'b1;
    end else begin
        reset_finish <= 1'b0;
    end
end

/**************************triggle gen******************************/

reg[5:0] last_state;
always @(posedge clk or negedge rst_n) begin
    if (rst_n) begin
        if (cur_state === last_state) begin
            state_changed_n <= 1'b1;
        end else begin
            state_changed_n <= 1'b0;
        end
        last_state <= cur_state;
    end else begin
        state_changed_n <= 1'b0;
    end
end

/**********************beheaver define****************************/
/*********************** address cycle **************************/
reg[3:0] addCounter;
always @(negedge clk or negedge add_cycle_tri_n or negedge rst_n) begin
    if (rst_n) begin
        if (add_cycle_tri_n === 1'b1) begin
            if (address_cycle === 1'b0 & addCounter < address_number) begin
                cmd_r_a <= State_adderss;
                if (port_data_in_en & rb_s_w) begin
                    data_r_a <= address_reg[7:0];
                    address_reg <= address_reg >> 8;
                    addCounter <= addCounter + 1'b1;
                end else begin
                    data_r_a <= data_r_a;
                    address_reg <= address_reg;
                    addCounter <= addCounter;                    
                end 
            end else begin
                address_cycle <= 1'b1;
                addCounter <= 4'h0;
                cmd_r_a <= State_Idle;
            end
        end else if(add_cycle_tri_n === 1'b0) begin
            address_cycle <= 1'b0;
            addCounter <= 4'h0;
        end else begin
            address_cycle <= 1'b1;
            addCounter <= 4'h0;
        end
    end else begin
        address_cycle <= 1'b1;
        addCounter <= 4'h0;
        add_cycle_tri_n <= 1'b1;
     //   address_reg <= 40'h12_34_56_78_9A;
    end
end

always @(posedge clk or posedge address_cycle or negedge rst_n) begin
    if (rst_n & clk === 1'b0 & address_cycle === 1'b1) begin
        add_cycle_fin_n <= 1'b0;
    end else begin
        add_cycle_fin_n <= 1'b1;
    end
end

/*********************** command cycle **************************/
reg cmdState;
always @(negedge clk or negedge cmd_cycle_tri_n or negedge rst_n) begin
    if (rst_n) begin
        if (cmd_cycle_tri_n === 1'b1) begin
            if (command_cycle === 1'b0 & cmdState === 1'b0) begin
               cmd_r_c <= State_command; 
               if (port_data_in_en & rb_s_w) begin
                    data_r_c <= command_reg;
                    cmdState = 1'b1;
                end else begin
                    data_r_c <= data_r_c;                     
                end
            end else begin
                command_cycle <= 1'b1;
                cmd_r_c <= State_Idle;
                data_r_c <= data_r_c;
            end
        end else if(cmd_cycle_tri_n === 1'b0) begin
            command_cycle <= 1'b0;
            cmdState <= 1'b0;
        end else begin
            command_cycle <= 1'b1;
            cmdState <= 1'b0;
        end
    end else begin
        command_cycle <= 1'b1;
        cmdState <= 1'b0;
        cmd_cycle_tri_n <= 1'b1;
    end
end

always @(posedge clk or posedge command_cycle or negedge rst_n) begin
    if (rst_n & clk === 1'b0 & command_cycle === 1'b1) begin
        cmd_cycle_fin_n <= 1'b0;
    end else begin
        cmd_cycle_fin_n <= 1'b1;
    end
end

/*********************** read data cycle **************************/
reg[7:0] readed;

task read_data;
    if (cur_state === READ_ID || cur_state === GET_FEATURES) begin
        features_reg <= {features_reg[23:0], port_data_out_reg};
    end else begin
        AHBwrite_fifo <= {AHBwrite_fifo[WRITE_FIFO_SIZE - 8:0], port_data_out_reg};
        AHBwrite_fifo_counter <= AHBwrite_fifo_counter + 8;
     //   readed <= port_data_out_reg;
    end
endtask

always @(negedge clk or negedge rd_cycle_tri_n or negedge rst_n) begin
    if (rst_n) begin
        if (rd_cycle_tri_n === 1'b1) begin
            if (read_data_counter < read_data_number & read_data_cycle === 1'b0) begin
                cmd_r_rd <= State_ReadData;
                if (port_data_out_vaild & rb_s_w) begin
                    read_data;
                    read_data_counter <= read_data_counter + 1'b1;
                end else begin
                    read_data_counter <= read_data_counter;
                end
            end else begin
                read_data_cycle <= 1'b1;
                cmd_r_rd <= State_Idle;
            end
        end else if(rd_cycle_tri_n === 1'b0) begin
            read_data_cycle <= 1'b0;
            cmd_r_rd <= State_Idle;
            read_data_counter <= 32'h0;
        end
    end else begin
        read_data_cycle <= 1'b1;
        cmd_r_rd <= State_Idle;
        read_data_counter <= 32'h0;
        rd_cycle_tri_n <= 1'b1;
    end
end

always @(posedge clk or posedge read_data_cycle or negedge rst_n) begin
    if (rst_n & clk === 1'b0 & read_data_cycle === 1'b1) begin
        rd_cycle_fin_n <= 1'b0;
    end else begin
        rd_cycle_fin_n <= 1'b1;
    end
end

/*********************** write data cycle **************************/
wire[7:0] inputData;
reg       wait_ecc;

task write_data;
    begin
        if (cur_state === SET_FEATRES) begin
            data_r_wd <= features_reg;
            features_reg <= features_reg >> 8;
        end else begin
            if (AHBread_fifo_counter <= 8 & write_data_counter < write_data_number - SPARE_SIZE - 1) 
                waite_for_AHBread <= 1;
            else 
                waite_for_AHBread <= 0;

            if (write_data_counter < write_data_number - SPARE_SIZE) begin
                data_r_wd = AHBread_fifo >> (AHBread_fifo_counter - 8);
                AHBread_fifo_counter <= AHBread_fifo_counter - 8;
            end else begin
                //read ecc
                data_r_wd <= LDPC_CODEREAD_FIFO >> (ldpc_codeRead_FIFOcounter - 8);    
                ldpc_codeRead_FIFOcounter <= ldpc_codeRead_FIFOcounter - 8;            
            end
        end
    end
endtask

always @(negedge clk or negedge wd_cycle_tri_n or negedge rst_n) begin
    if (rst_n) begin
        if (wd_cycle_tri_n === 1'b1) begin
            if (write_data_cycle === 1'b0 & write_data_counter <= write_data_number) begin
                if (write_data_counter === write_data_number - SPARE_SIZE & ecc_ready === 1'b0) begin
                    cmd_r_wd <= State_WriteWait;
                    data_r_wd <= data_r_wd;
                    wait_ecc <= 1'b1;
                end else if(waite_for_AHBread) begin
                    cmd_r_wd <= State_WriteWait;
                    data_r_wd <= data_r_wd;
                end else begin
                    cmd_r_wd <= State_WriteData;
                    if (port_data_in_en & rb_s_w) begin
                        write_data;
                        write_data_counter <= write_data_counter + 1'b1;
                    end else begin
                        data_r_wd <= data_r_wd;
                        write_data_counter <= write_data_counter;
                    end
                end
            end else begin
                data_r_wd <= 8'hff;
                write_data_cycle <= 1'b1;
                write_data_counter <= 32'h0;
                cmd_r_wd <= State_Idle;
            end
        end else if (wd_cycle_tri_n === 1'b0) begin
            write_data_cycle <= 1'b0;
            write_data_counter <= 32'h0;
            cmd_r_wd <= State_WriteData;
        end
    end else begin
        data_r_wd <= 8'hff;
        write_data_cycle <= 1'b1;
        cmd_r_wd <= State_WriteData;
        write_data_counter <= 32'h0;
        wait_ecc <= 1'b0;
        wd_cycle_tri_n <= 1'b1; 
    end
end

always @(posedge clk or posedge write_data_cycle or negedge rst_n) begin
    if (rst_n & clk === 1'b0 & write_data_cycle === 1'b1) begin
        wd_cycle_fin_n <= 1'b0;
    end else begin
        wd_cycle_fin_n <= 1'b1;
    end
end

/************************** delay cycle *****************************/
reg[8:0] dly_counter;
always @(negedge clk or negedge dly_cycle_tri_n or negedge rst_n) begin
    if (rst_n) begin
        if (dly_cycle_tri_n === 1) begin
            if (delay_cycle === 0 & dly_counter < delay_number) begin
                dly_counter <= dly_counter + 1;
            end else begin
                delay_cycle <= 1'b1;
                dly_counter <= dly_counter;
            end
        end else begin
            delay_cycle <= 1'b0;
            dly_counter <= 8'h00;
        end
    end else begin
        delay_cycle <= 1'b1;
        dly_counter <= 8'hff;
        dly_cycle_tri_n <= 1'b0;
    end
end

always @(posedge clk or posedge delay_cycle or negedge rst_n) begin
        if (rst_n & clk === 1'b0 & delay_cycle === 1'b1) begin
        dly_cycle_fin_n <= 1'b0;
    end else begin
        dly_cycle_fin_n <= 1'b1;
    end
end

/************************** wait rnb cycle *****************************/

always @(negedge clk or negedge wait_rnb_tri_n or negedge rst_n) begin
    if (rst_n) begin
        if (wait_rnb_tri_n === 1) begin
            if (wait_rnb_cycle === 0 & rb_s_w === 0) begin
                wait_rnb_cycle <= 0;
            end else begin
                wait_rnb_cycle <= 1;
            end
        end else begin
            wait_rnb_cycle <= 1'b0;
        end
    end else begin
        wait_rnb_cycle <= 1;
        wait_rnb_tri_n <= 1'b1;
    end
end

always @(posedge clk or posedge wait_rnb_cycle or negedge rst_n) begin
        if (rst_n & clk === 1'b0 & wait_rnb_cycle === 1'b1) begin
        wait_rnb_fin_n <= 1'b0;
    end else begin
        wait_rnb_fin_n <= 1'b1;
    end
end

endmodule // NANDFlash_Control